#include "simple_epoll.hpp"

namespace mina
{
	SimpleEpoll::SimpleEpoll(int maxfds)
		:_revents(NULL)
	{
		init(maxfds);
	}

	SimpleEpoll::~SimpleEpoll()
	{
		SAFE_DELETE_ARR(_revents);
		close();
	}

	int SimpleEpoll::init(int maxfds)
	{
		_maxfds = maxfds;
		_revents = new epoll_event[_maxfds];
		_epfd = ::epoll_create(maxfds);
		if(_epfd < 0)
		{
			return -1;
		}

		return 0;
	}

	int SimpleEpoll::close()
	{
		return ::close(_epfd);
	}

	int SimpleEpoll::add(int fd, unsigned int events, void * conn)
	{
		struct epoll_event ev;

		ev.events   = events;
		ev.data.ptr = conn;

		return ::epoll_ctl(_epfd, EPOLL_CTL_ADD, fd, &ev);
	}

	int SimpleEpoll::mod(int fd, unsigned int events, void * conn)
	{
		struct epoll_event ev;

		ev.events   = events;
		ev.data.ptr = conn;

		return ::epoll_ctl(_epfd, EPOLL_CTL_MOD, fd, &ev);
	}

	int SimpleEpoll::del(int fd)
	{
		return ::epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, NULL);
	}

	int SimpleEpoll::wait(long timeout)
	{
		_next_idx   = 0;
		_last_idx   = 0;
		_last_idx   = ::epoll_wait(_epfd, _revents, _maxfds, timeout);
		if (_last_idx < 0 && ((errno == EAGAIN) || ( errno == EINTR)))
		{
			_last_idx = 0;
		}
		
		return _last_idx;
	}

	int SimpleEpoll::next(void *& conn, unsigned int & op)
	{
		if (_next_idx >= _last_idx)
		{
			return -1;
		}
		
		conn = _revents[_next_idx].data.ptr;
		op   = _revents[_next_idx].events;

		++ _next_idx;

		return 0;
	}
}

